#include <arpa/ip_addr.h>
#include <stdio.h>
#include <ctype.h>

u32_t ipaddr_addr(const char *cp)
{
    ip_addr_t val;
    if (ipaddr_aton(cp, &val))
    {
        return ip4_addr_get_u32(&val);
    }
    return IPADDR_NONE;
}

char *ipaddr_ntoa(const ip_addr_t *addr)
{
    static char str[16];
    return ipaddr_ntoa_r(addr, str, 16);
}

//translation the network addr to ascill string
char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buff, int bufflen)
{
    u32_t s_addr;
    u8_t *ap;
    char inv[4];
    u8_t rem;
    u8_t *rp;
    u32_t len = 0;
    u32_t n = 0;

    s_addr = ip4_addr_get_u32(addr);

    rp = buff;
    ap = (u8_t *)&s_addr;

    //deal with ip part
    for (int i = 0; i < 4; i++)
    {
        n = 0;
        //translation ip part to str
        do
        {
            rem = *ap % 10;
            *ap /= 10;
            inv[n++] = '0' + rem; //to ascii
        } while (*ap);

        //copy to targe buffer
        while (n--)
        {
            //above limit
            if (len > bufflen)
                return NULL;

            *rp++ = inv[n];
            len++;
        }

        if (len > bufflen)
            return NULL;
        //while ip part is 4,don not add '.'
        if (i != 4)
            *rp++ = '.'; //add '.' sign
        ap++;            //do next part
    }
    return buff;
}

u32_t ipaddr_aton(const char *cp, ip_addr_t *addr)
{
    u32_t val;
    u8_t base;
    char c;
    u32_t part[4];
    u32_t *pp = part;

    while (1)
    {
        if (!isdigit(c))
            return 0;
        val = 0;
        base = 10;
        //hex
        if (c == '0')
        {
            c = *++cp;
            if (c == 'x' || c == 'X')
            {
                base = 16;
                c = *++cp;
            }
            else
            {
                base = 8;
            }
        }

        //number to character
        while (1)
        {
            if (isdigit(c))
            {
                val = (val * base) + (c - '0');
                c = *++cp;
            }
            else
            {
                if (base == 16 && isxdight(c))
                {
                    val = (val << 4) | (c + 10 - (islower(c) ? 'a' : 'A'));
                    c = *++cp;
                }
                else
                {
                    break;
                }
            }
        }
        //format
        //a.b.c.d
        if (c == '.')
        {
            if (pp > part + 3)
                return 0;
            //next part
            *pp++ = val;
            c = *++cp;
        }
        else
        {
            break;
        }
    }
    //check for trailing character
    if (c != '\0' && !isspace(c))
        return 0;

    switch (pp - part + 1)
    {
    case 0: //a-32bits
        return 0;
    case 1:
        break;
    case 2: //a.b-8.24bits
        if (val > 0xffffffUL)
            return 0;
        val |= part[0] << 24;
        break;
    case 3: //a.b.c-8.8.16bits
        if (val > 0xffff)
            return 0;
        val |= (part[0] << 24) | (part[1] << 16);
        break;
    case 4: //a.b.c.d-8.8.8.8bits
        if (val > 0xff)
            return 0;
        val |= (part[0] << 24) | (part[1] << 16) | (part[2] << 8);
        break;
    default:
        perror("unhanedled!\n");
        break;
    }
    //set addr
    if (addr)
    {
        ip4_addr_set_u32(addr, htonl(val));
    }
    return 1;
}